﻿import My3D.Polygon;
import flash.geom.Point;
import mx.utils.Delegate;
import My3D.Face;
import My3D.Point3D;
import My3D.Testure;

dynamic class My3D.Screen extends MovieClip {
	
	//--------------------------------------------------------------------------------------
	//																					private 
	private var $rootmc:MovieClip;
	
	private var $Faces:Object;
	private var $FaceArr:Array;
	private var $Polygon:Object;
	
	private var $updataFace:Object;
	
	private var $RenderingMc:MovieClip;
	private var $testure:Testure;
	
	private var $updataAllFaces:Boolean = false;
	
	private var $RenderedFaceCount:Number = 0;
	
	public var testureSingleFace:Boolean = true;
	//--------------------------------------------------------------------------------------
	//																					public 
	/**
	 * the count of face which has been Rendered in this frame
	 */
	public function get RenderedFaceCount():Number {
		return this.$RenderedFaceCount
	}
	public function get RootMc():MovieClip {
		return this.$rootmc;
	}
	
	//--------------------------------------------------------------------------------------
	//																					function 
	public function Screen(rootmc:MovieClip) {
		initsay();
		if (rootmc == undefined) {
			rootmc = this;
		}
		if (rootmc == undefined) {
			_say.esay("not set root mc.");
			return;
		}
		this.$rootmc = rootmc;
		initvars();
		initONEEF();
		_say.msay("inited!");
	}
	private function initONEEF() {
		this.$RenderingMc = this.$rootmc.createEmptyMovieClip("_screenRenderingMc", 1);
		this.$RenderingMc.onEnterFrame = Delegate.create(this, this.renderingMcOEEF);
	}
	private function renderingMcOEEF() {
		var count:Number = 0;
		this.projectPoints();
		
		
		if (!this.$updataAllFaces) {
			var toReandArr:Array = new Array();
			
			for (var i:String in this.$updataFace) {
				count++;
				toReandArr.push(this.$updataFace[i]);
				delete this.$updataFace[i];
			}
			if (count > 0) {
				this.$rootmc.clear();
			}
			toReandArr.sort(this.compDep);
			var f:Face;
			
			while (f = Face(toReandArr.pop())) {
				this.renderingFace(f);
			}
		}else {
			count=this.renderingAllFaceNow();
		}
		this.$RenderedFaceCount = count;
	}
	private function compDep(f1:Face, f2:Face):Number {
		return (f1.getZ() > f2.getZ())? -1:1;
	}
	/**
	 * set points porjected location
	 */
	private function projectPoints() {
		for (var i:String in this.$Faces) {
			var pa:Point = this.projectPoint(this.$Faces[i].$pointA);
			var pb:Point = this.projectPoint(this.$Faces[i].$pointB);
			var pc:Point = this.projectPoint(this.$Faces[i].$pointC);
			this.$Faces[i].$pointA.X = pa.x;
			this.$Faces[i].$pointA.Y = pa.y;
			this.$Faces[i].$pointA.Z = this.$Faces[i].$pointA.z;
			
			this.$Faces[i].$pointB.X = pb.x;
			this.$Faces[i].$pointB.Y = pb.y;
			this.$Faces[i].$pointB.Z = this.$Faces[i].$pointB.z;
			
			this.$Faces[i].$pointC.X = pc.x;
			this.$Faces[i].$pointC.Y = pc.y;
			this.$Faces[i].$pointC.Z = this.$Faces[i].$pointC.z;
		}
		for (var i in this.$Polygon) {
			this.$Polygon[i].ProjectPoints();
		}
	}
	/**
	 * initlize paramentes
	 */
	private function initvars() {
		this.$Faces = new Object();
		this.$FaceArr = new Array();
		this.$Polygon = new Object();
		this.$updataFace = new Object();
		Face.Updataed = Delegate.create(this, this.UpdataFace);
		this.$testure = new Testure(this);
	}
	public function UpdataFace(face:Face) {
		if (face == undefined) {
			this.$updataAllFaces = true;
			return;
		}
		if (this.$updataFace[face.ID] == undefined) {
			this.$updataFace[face.ID] = face;
		}
	}
	public function AddPolygon(p:Polygon) {
		if(this.$Polygon[p.polygonName]==undefined){
			for (var i = 0; i < p.faces.all.length; i++) {
				this.AddFace(p.faces.all[i]);
				//p.projectPointFun = this.projectPoint;
			}
			this.$Polygon[p.polygonName] = p;
		}
	}
	public function DelPolygon(p:Polygon) {
		delete this.$Polygon[p.polygonName];
	}
	public function AddFace(f:Face) {
		if (this.$Faces[f.ID] != undefined) {
			return false
		}else {
			this.$Faces[f.ID] = f;
			this.$FaceArr.push(f);
			return true;
		}
	}
	public function RemoveFace(f:Face) {
		
		for (var i:Number = 0; i < this.$FaceArr.length; i++ )
		{
			if (this.$FaceArr[i].ID == f.ID )
			{
				this.$FaceArr.splice(i, 1);
			}
		}
		delete this.$Faces[f.ID];
	}
	////////////////////////////////////////////////////////////////      Project
	public function projectPoint(p:Point3D):Point {
		// hear need more project functions
		return new Point(p.x, p.y);
	}
	
	////////////////////////////////////////////////////////////////      Rendering
	/**
	 * rendering all face Immediately
	 */
	public function renderingAllFaceNow():Number {
		var count:Number = 0;
		this.$rootmc.clear();
		//Z排序
		this.$FaceArr.sort(this.compDep);
		for (var i:Number = 0; i < this.$FaceArr.length; i++ ) {
			this.renderingFace(this.$FaceArr[i]);
			count++;
		}
		return count;
	}
	/**
	 * render a face
	 * @param	face face to render
	 */
	private function renderingFace(face:Face) {
		if (face != null) {
			this.$testure.testureFace(face);
		}
	}
	
	
	
	
	////////////////////////////////////////////////////////////////      output
	private var _say:Say;
	private function initsay() {
		_say = new Say("Screen");
		_say.addListener(this);
		this[Say.M_SAY] = this.sayfun;
	}
	private function sayfun(o) {
		trace(o);
	}
	
}